/**
 * Clase que contiene todas las herramientas necesarias para Spider.
 * 
 * @author HPCIII_Team2013
 */
package cl.ucn.hpc.webCrawler;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.util.List;

import cl.ucn.hpc.almacenamiento.Storage;
import cl.ucn.hpc.almacenamiento.BlockingStorage;
import cl.ucn.hpc.descarga.Download;
import cl.ucn.hpc.procesamiento.HTMLProcessing;

public class Tools {
	protected static Storage storage;
	protected BlockingStorage blockStorage;

	/**
     * Contructor de la clase.
     * 
     * @param path Directorio general donde debe almacenar la informacion recibida
     */
	public Tools(String path) {
		storage = new Storage(path);
		blockStorage = BlockingStorage.getInstance(path);
	}

	/**
     * Obtiene el contenido integro de la pagina descargada.
     * 
     * @param url Link de la pagina a descargar.
     * @return Pagina completa con sus anotacions HTML incluidas.
     * @throws IOException Si no puede crear el InputStream.
     * @throws IllegalArgumentException Si hay problemas con el fetch.
     * @throws MalformedURLException Si hay problemas con la url.
     */
	protected InputStream fetch(final String url) throws IOException, IllegalArgumentException, MalformedURLException{
		InputStream input = Download.fetch(url);
		return input;
	}

	/**
     * Obtiene el nombre de la pagina entregada.
     * 
     * @param url Link de la pagina solicitada.
     * @return Nombre de la pagina.
     * @throws IOException Si no puede acceder a la pagina.
     */
	protected String host(final String url) throws IOException {
		String input = Download.host(url);
		return input;
	}
	
	/**
     * Convierte el archivo recibido a texto.
     * 
     * @param is Archivo a convertir.
     * @return Texto del archivo recibido.
     */
	private static String getStringFromInputStream(InputStream is) {
		if (is == null) {
			return null;
		}

		BufferedReader br = null;
		StringBuilder sb = new StringBuilder();

		String line;
		try {
			br = new BufferedReader(new InputStreamReader(is));
			while ((line = br.readLine()) != null) {
				sb.append(line);
			}
			
		} catch (IOException e) {
			return "";
		} finally {
			if (br != null) {
				try {
					br.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}

		return sb.toString();
	}

	/**
     * Convierte el archivo recibido a texto.
     * 
     * @param url Archivo. 
     * @return Texto del archivo recibido.
     * @throws IOException Si no puede convertir el archivo.
     */
	protected String htmltext(final InputStream url) throws IOException {
		String text = getStringFromInputStream(url);

		return text;
	}

    /**
     * Guarda el archivo recibido.
     * 
     * @param input Archivo a almacenar.
     * @return El archivo creado para almacenarlo
     * @throws IOException Si no puede convertir el archivo.
     */	
	protected File save(InputStream input, String name) throws IOException {
		File file = storage.save(input, name);
		return file;
	}

    /**
     * Guarda el texto recibido.
     * 
     * @param input Texto a almacenar.
     * @param name Nombre del archivo donde se guardara.
     * @return archivo creado.
     * @throws IOException Si no puede crear el archivo.
     */
	protected File save(String input, String name, String url) throws IOException {
		File file = storage.save(input, name);
		return file;
	}
	
    /**
     * Guarda el texto recibido.
     * 
     * @param input Texto a almacenar.
     * @param name Nombre del archivo donde se guardara.
     * @return archivo creado.
     * @throws IOException Si no puede crear el archivo.
     */
	protected File blockingSave(String input, String name) throws IOException {
		File file = blockStorage.blockingSave(input, name);
		return file;
	}
	
    /**
     * Guarda la lista de textos recibidos.
     * 
     * @param input Textos a almacenar.
     * @param name Nombre del archivo donde se guardara.
     * @return archivo creado.
     * @throws IOException Si no puede crear el archivo.
     */
	protected File save(List<String> images, String name) throws IOException{
		File file = storage.save(images, name);
		return file;
	}

	/**
     * Elimina las anotaciones HTML del archivo recibido.
     * 
     * @param htmlfile Archivo con la pagina recibida.
     * @return Texto del archivo sin anotaciones HTML.
     * @throws IOException Si ocurre un error con el archivo.
     */
	protected String text(File htmlfile) throws IOException {
		String tex = HTMLProcessing.extractText(htmlfile);
		return tex;
	}

	/**
     * Extrae las anotaciones HTML del texto recibido.
     * 
     * @param htmlfile Texto que contiene anotaciones HTML.
     * @return Texto sin anotaciones HTML.
     * @throws IOException Si ocurre un error con la extracion de HTML.
     */
	protected String text(String htmlfile) throws IOException {
		String tex = HTMLProcessing.extractText(htmlfile);
		return tex;
	}

	/**
     * Extrae los links de la pagina recibida.
     * 
     * @param htmlfile Archivo con la pagina recibida.
     * @return Listado con los links de las paginas encontradas.
     * @throws IOException Si ocurre un error en la extraccion de links.
     */
	protected List<String> links(File htmlfile) throws IOException {
		List<String> links = HTMLProcessing.extractLinks(htmlfile);
		return links;
	}

	/**
     * Extrae los links del texto recibido.
     * 
     * @param htmlfile Texto que puede contener links.
     * @return Lista con los links de las paginas encontradas.
     * @throws IOException Si ocurre un problema en la extraccion de links.
     */
	protected List<String> links(String htmlfile) throws IOException {
		List<String> links = HTMLProcessing.extractLinks(htmlfile);
		return links;
	}

	/**
     * Extrae los links de las imagenes contenidas en la pagina recibida.
     * 
     * @param htmlfile Archivo que contiene la pagina recibida.
     * @return Lista con los links de las imagenes encontradas.
     * @throws IOException Si ocurre un error extrayendo los links de las imagenes.
     */
	protected List<String> images(File htmlfile) throws IOException {
		List<String> links = HTMLProcessing.extractImageUrl(htmlfile);
		return links;
	}

	/**
     * Extrae los links de las imagenes contenidas en el texto recibido.
     * 
     * @param htmlfile Texto que puede contener vinculos de imagenes.
     * @return Lista con los links de las imagenes encontradas.
     * @throws IOException Si ocurre un error extrayendo los links de las imagenes.
     */
	protected List<String> images(String htmlfile) throws IOException{
		List<String> links = HTMLProcessing.extractImageUrl(htmlfile);
		return links;
	}
	
	/**
     * Cuenta la cantidad de lineas en el archivo especificado.
     * 
     * @param filename Archivo en el cual se contaran las lineas.
     * @return Cantidad de lineas contadas.
     * @throws IOException Si no se encuentra el archivo especificado.
     */
	protected int lineCount(String filename) throws IOException {			
	    InputStream is = new BufferedInputStream(new FileInputStream(storage.getFilePath()+ File.separatorChar +filename));
	    try {
	        byte[] c = new byte[1024];
	        int count = 0;
	        int readChars = 0;
	        boolean empty = true;
	        while ((readChars = is.read(c)) != -1) {
	            empty = false;
	            for (int i = 0; i < readChars; ++i) {
	                if (c[i] == '\n') {
	                    ++count;
	                }
	            }
	        }
	        return (count == 0 && !empty) ? 1 : count;
	    }finally {
	    	if (is != null)
	    		is.close();
	    }
	}
	
	/**
	 * Busca en que linea se encuentra la cadena entregada.
	 * 
	 * @param archivo Donde se debe buscar la cadena.
	 * @param cadenaBuscada Cadena que se debe buscar en el archivo.
	 * @return numero de la linea donde se encontro el string.
	 */
	 public static int lineChain(String nomArchivo, String cadenaBuscada) throws IOException{    	
    	BufferedReader reader = new BufferedReader(new FileReader(storage.getFilePath()+ File.separatorChar + nomArchivo));
    	String line = null;
    	int numLinea = 1;
    	
    	while ((line = reader.readLine()) != null) {
    	    if(line.trim().toUpperCase().equals(cadenaBuscada.trim().toUpperCase())){
    	    	reader.close();
    	    	return numLinea;
    	    }
    	    numLinea++;
    	}
    	
    	reader.close();
    	return -1;
    }
}
